// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-11-17

#include "stdafx.h"
#include "svr_usersocket.h"
#include "svr_userset.h"
#include "svr_user.h"
#include "svr_netmsg.h"

namespace JoyServer
{

class CJoyUserRecvDataMsg : public CJoyUserSetMsg
{
public:
    CJoyTransmitData* m_recvData;

    virtual void OnExecute(CJoyUser* pUser);

    CJoyUserRecvDataMsg(CJoyTransmitData* recvData)
    {
        m_recvData = recvData;
        recvData->AddRef();
    }
    virtual ~CJoyUserRecvDataMsg()
    {
        if(m_recvData != NULL)
        {
            m_recvData->Release();
        }
    }
};

void CJoyUserRecvDataMsg::OnExecute(CJoyUser* pUser)
{
    BYTE* pBuf = (BYTE*)m_recvData->m_buf.GetBuffer();
    int   nLen = m_recvData->m_buf.GetSize();

    CJoyBuffer& partBuf = pUser->m_socket.m_partBuf;
    if(!partBuf.IsEmpty())
    {
        partBuf.Append(pBuf, nLen);
        pBuf = (BYTE*)partBuf.GetBuffer();
        nLen = partBuf.GetSize();
    }

    while(nLen > sizeof(int))
    {
        int packLen = *(int*)pBuf;
        if(packLen > JOY_USER_MSG_MAX || packLen < 0)
        {
            pUser->OnError(UserError_SockBadData);
            return;
        }
        int packAllLen = packLen+sizeof(int);
        if(packAllLen > nLen)
        {
            break;
        }
        void* pack  = pBuf+sizeof(int);
        pBuf += packAllLen;
        nLen -= packAllLen;

        JoyMessage::MessageBase* msg = JoyMsgTool::ExtractMsg(pack, packLen);
        if(msg == NULL)
        {
            pUser->OnError(UserError_SockBadData);
            return;
        }
        pUser->NetMsg_Recv(msg);
    }

    if(nLen > 0)
    {
        if(partBuf.IsEmpty())
        {
            partBuf.Append(pBuf, nLen);
        }
        else
        {
            partBuf.Remove(pBuf);
            ASSERT(partBuf.GetSize() == nLen);
        }
    }
    else
    {
        partBuf.RemoveAll();
    }
}

// class CJoyUserSocket

CJoyUserSocket::CJoyUserSocket()
{
}

CJoyUserSocket::~CJoyUserSocket()
{
}

bool CJoyUserSocket::Send(CJoyTransmitData* sendData, int& err)
{
    if(m_sockData == NULL)
    {
        return false;
    }
    if(m_sockData->m_sendCount > JOY_USER_MSG_SENDING_MAX)
    {
        GetUser()->OnError(UserError_SockMaxSending);
        return false;
    }

    return __super::Send(sendData, err);
}

void CJoyUserSocket::SendMsg(const JoyMessage::MessageBase* pMsg)
{
    if(m_sockData == NULL)
    {
        return;
    }

    CJoyTransmitData* pData = JoyMsgTool::BuildMsgData(pMsg);
    int err;
    Send(pData, err);
    pData->Release();
}

void CJoyUserSocket::OnError(int err)
{
    CJoyUser* pUser = GetUser();
    pUser->OnSockError(err);
}

void CJoyUserSocket::OnRecv(CJoyTransmitData* recvData, const sockaddr_in&)
{
    CJoyUser* pUser = GetUser();
    CJoyUserRecvDataMsg* pMsg = new CJoyUserRecvDataMsg(recvData);
    pUser->QueueUserSetMsg(pMsg);
}

template<typename MsgType>
void CJoyNetMsgHandler::NetMsg_Dispatch(const MsgType* msg, void (CJoyNetMsgHandler::*pHandler)(const MsgType*))
{
    if(!msg->IsValid())
    {
        NetMsg_BadData(msg);
        return;
    }

    (this->*pHandler)(msg);
}

void CJoyNetMsgHandler::NetMsg_Recv(const JoyMessage::MessageBase* msg)
{
    switch(msg->m_type)
    {
#   define JOY_MSG_CLIENT_DEF(name) case JoyMessage::MCT_##name: NetMsg_Dispatch((JoyMessage::MC_##name*)msg, &JoyServer::CJoyNetMsgHandler::OnNetMsg_##name); break;
#   include <common\netmsg\mc_def.h>
    }
}

} // namespace JoyServer